
#include <stdio.h>
#include <time.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <fstream>

#include <stdexcept>

#include <cxcore.h>
#include <cv.h>
#include <highgui.h>

#include <boost/smart_ptr.hpp>

#include "basic_utils.hh"
#include "AppearanceBase.hh"

int AppearanceBase::save(const char *file)
{

    if(!CV_IS_IMAGE(mean.get()) || vectors.size()==0)
	return 1;
    
    char str[200];
    boost::shared_ptr<CvFileStorage> fs;

    fs.reset(cvOpenFileStorage(file, NULL, CV_STORAGE_WRITE), deleteFileStorage);

    if(fs.get() == NULL){
	std::cerr << "AppearanceBase::save(): Bad File" << std::endl;
	return -1;
    }

    if(!vector_as_row){
	cvWrite(fs.get(), "mean", mean.get());
	if(CV_IS_MAT(eigvals.get()))
	    cvWrite(fs.get(), "eigenvalues", eigvals.get());
	
	
	for(unsigned int ai=0; ai<vectors.size(); ai++){
	    sprintf(str, "vector_%05d", ai);
	    
	    cvWrite(fs.get(), str, vectors.at(ai).get());	
	}
    }
    else{
	CvMat mat, row;
	IplImage img;

	cvReshape(mean.get(), &mat, 0, sz.height);
	cvGetImage(&mat, &img);
	cvWrite(fs.get(), "mean", &img);

	if(CV_IS_MAT(eigvals.get()))
	    cvWrite(fs.get(), "eigenvalues", eigvals.get());

	for(unsigned int ai=0; ai<nvectors; ai++){
	    cvGetRow(vectors.at(0).get(), &row, ai);
	    cvReshape(&row, &mat, 0, sz.height);
	    cvGetImage(&mat, &img);

	    sprintf(str, "vector_%05d", ai);
	    
	    cvWrite(fs.get(), str, &img);	
	}
    }
    

    return 0;
}


int AppearanceBase::load(const char *file, bool vect_as_row)
{
    boost::shared_ptr<CvFileStorage> fs;
    CvFileNode *node;

    clear();

    //open the FileStorage

    fs.reset(cvOpenFileStorage(file, NULL, CV_STORAGE_READ), deleteFileStorage);
    if(fs.get() == NULL){
	std::cerr << "AppearanceBase::save(): Bad File" << std::endl;
	return -1;
    }

    //get the mean
    node = cvGetFileNodeByName(fs.get(), NULL, "mean");
    if(!node){
	std::cerr << "No mean appearance found" << std::endl;
	return -1;
    }
    IplImage * img = (IplImage*)cvRead(fs.get(), node);
    if(!CV_IS_IMAGE(img)){
	std::cerr << "Invalid mean apperance found" << std::endl;
	return -1;
    }
    mean.reset(img, deleteIplImage);
    sz = cvGetSize(mean.get());
    
    node = cvGetFileNodeByName(fs.get(), NULL, "eigenvalues");
    if(!node){
	std::cerr << "No eigenvalues found" << std::endl;
    }
    else{
	CvMat *mat = (CvMat*)cvRead(fs.get(), node);
	if(!CV_IS_MAT(mat)){
	    std::cerr << "Invalid eigenvalues found" << std::endl;
	    return -1;
	}
	//sqrt
	cvPow(mat, mat, 0.5);
	eigvals.reset(mat, deleteCvMat);
    }

    char str[200];
    for(uint ai=0; ;ai++){
	sprintf(str, "vector_%05d", ai);
	node = cvGetFileNodeByName(fs.get(), NULL, str);
	if(!node)
	    break;

	img = (IplImage*)cvRead(fs.get(), node);
	if(!CV_IS_IMAGE(img)){
	    std::cerr << "Invalid apperance vector "<< ai <<" found" << std::endl;
	    return -1;
	}

	boost::shared_ptr<IplImage> vec (img, deleteIplImage);
	vectors.push_back(vec);
    }

    nvectors = vectors.size();
    std::cout << nvectors << " vectors loaded. "<<std::endl;

    //convert the mean and vectors to rows
    if(vect_as_row){
	
	boost::shared_ptr<IplImage> m (cvCreateImage(cvSize(mean->width*mean->height,1),
						     mean->depth, mean->nChannels), deleteIplImage);
	CvMat submat, row;
	IplImage imgh;
	cvReshape(mean.get(), &submat, 0, 1);
	cvGetImage(&submat, &imgh);
	cvCopy(&imgh, m.get());
	
	mean = m;
	
	boost::shared_ptr<IplImage> v (cvCreateImage(cvSize(mean->width, nvectors),
						     mean->depth, mean->nChannels), deleteIplImage);
	
	for(uint ai=0; ai<nvectors; ai++){
	    cvReshape(vectors.at(0).get(), &submat, 0, 1);
	    cvGetRow(v.get(), &row, ai);
	    cvCopy(&submat, &row);
	}

	vectors.clear();
	vectors.push_back(v);

    }
    vector_as_row = vect_as_row;


    return 0;
}

